#include <fmt/ranges.h>
#include <spdlog/spdlog.h>

#include <climits>
#include <vector>

#include "agent/agent.h"
#include "agent/player_info.h"
#include "agent/position.h"
#include "agent/supply.h"
#include "path_finding.h"
// 射程相关
static const int range_kAwm = 10;
static const int range_kM16 = 100;
static const int range_kS686 = 50;
static const int range_kVector = 50;
// 状态相关
static bool got_weapon = false;
static bool got_bullet = false;
static bool got_weapon_and_bullet = false;
// 子弹相关
static int bullet_pos_min = INT_MAX;
thuai7_agent::Supply nearest_bullet;

constexpr auto kFloatPositionShift = 0.5;

static struct {
  std::vector<thuai7_agent::Position<int>> path;
} state;

void Setup(thuai7_agent::Agent& agent) {
  int loop = 0;
  thuai7_agent::SupplyKind weapon_;
  thuai7_agent::SafeZone safezone_ = agent.safe_zone().value().get();
  std::vector<thuai7_agent::Position<float>> bullet_position;
  for (auto& supply : agent.supplies().value().get()) {
    if (supply.kind == thuai7_agent::SupplyKind::kBullet &&
        pow(safezone_.center.x - supply.position.x, 2) +
                pow(safezone_.center.y - supply.position.y, 2) <
            pow(safezone_.radius - 30, 2)) {
      bullet_position.push_back(supply.position);
    }
  }
  if (bullet_position.size() == 0) loop = 4;
  thuai7_agent::Position<float> SpwanPoint;
  do {
    if (loop == 0)
      weapon_ = thuai7_agent::SupplyKind::kAwm;
    else if (loop == 1)
      weapon_ = thuai7_agent::SupplyKind::kM16;
    else if (loop == 2)
      weapon_ = thuai7_agent::SupplyKind::kVectory;
    else if (loop == 3)
      weapon_ = thuai7_agent::SupplyKind::kS686;
    else if (loop == 4)
      weapon_ = thuai7_agent::SupplyKind::kPremiumArmor;
    else if (loop == 5)
      weapon_ = thuai7_agent::SupplyKind::kPrimaryArmor;
    std::vector<thuai7_agent::Position<float>> supply_position;
    for (auto& supply : agent.supplies().value().get()) {
      if (supply.kind == weapon_ &&
          pow(safezone_.center.x - supply.position.x, 2) +
                  pow(safezone_.center.y - supply.position.y, 2) <
              pow(safezone_.radius - 30, 2)) {
        supply_position.push_back(supply.position);
      }
    }
    if (supply_position.size() != 0) {
      float min = 256 * 256;
      for (auto& bullet_pos : bullet_position) {
        for (auto& supply_pos : supply_position) {
          float dis = pow(bullet_pos.x - supply_pos.x, 2) +
                      pow(bullet_pos.y - supply_pos.y, 2);
          if (dis < min) {
            min = dis;
            SpwanPoint = bullet_pos;
          }
        }
      }
      loop = -1;
    }
    spdlog::debug("looping");
  } while (loop++ != -1);
  thuai7_agent::Position<float> origin_pos{SpwanPoint.x, SpwanPoint.y};
  agent.ChooseOrigin(origin_pos);
  spdlog::debug("done");
  // Your code here.
}

// 实现loop的逻辑
void Loop(thuai7_agent::Agent& agent) {
  auto const& player_info_list = agent.all_player_info().value().get();
  auto const self_id = agent.self_id().value();
  auto const& self_info = player_info_list.at(self_id);
  auto const& opponent_info = player_info_list.at(1 - self_info.id);

  auto const& map = agent.map().value().get();

  auto self_position_int =
      thuai7_agent::Position<int>{static_cast<int>(self_info.position.x),
                                  static_cast<int>(self_info.position.y)};
  auto opponent_position_int =
      thuai7_agent::Position<int>{static_cast<int>(opponent_info.position.x),
                                  static_cast<int>(opponent_info.position.y)};
  // 检查是否有道具可以拾取

  // 转换角色的位置为浮点数
  auto self_position_float = thuai7_agent::Position<float>{
      static_cast<float>(self_position_int.x + kFloatPositionShift),
      static_cast<float>(self_position_int.y + kFloatPositionShift)};

  // 检查脚底是否存在可拾取的道具
  auto supplies = agent.supplies().value().get();
  for (const auto& supply : supplies) {
    if (std::abs(supply.position.x - self_position_float.x) <= 1.0f &&
        std::abs(supply.position.y - self_position_float.y) <= 1.0f) {
      agent.PickUp(supply.kind, 1);
      // 如果捡到了武器，按照AWM>M16>冲锋枪>霰弹枪的规则切换
      if (supply.kind == thuai7_agent::SupplyKind::kAwm) {
        if (self_info.firearm != thuai7_agent::FirearmKind::kAwm) {
          agent.SwitchFirearm(thuai7_agent::FirearmKind::kAwm);
          spdlog::info("switched to Awm!");
        }
      } else if (supply.kind == thuai7_agent::SupplyKind::kM16) {
        if (self_info.firearm != thuai7_agent::FirearmKind::kM16) {
          agent.SwitchFirearm(thuai7_agent::FirearmKind::kM16);
          spdlog::info("switched to M16!");
        }
      } else if (supply.kind == thuai7_agent::SupplyKind::kS686) {
        if (self_info.firearm != thuai7_agent::FirearmKind::kS686) {
          agent.SwitchFirearm(thuai7_agent::FirearmKind::kS686);
          spdlog::info("switched to S686!");
        }
      } else if (supply.kind == thuai7_agent::SupplyKind::kVectory) {
        if (self_info.firearm != thuai7_agent::FirearmKind::kVector) {
          agent.SwitchFirearm(thuai7_agent::FirearmKind::kVector);
          spdlog::info("switched to vector!");
        }
      }
      got_weapon = true;
      break;
    }
  }

  // 如果没有子弹先去拾取子弹
  if (!got_bullet && got_weapon) {
    spdlog::info("Start to pick up bullet!");
    // 捡起武器后需要找到距离最近的子弹位置捡起子弹
    // thuai7_agent::Position<int> bullet_position_int;
    // for (const auto& supply : supplies) {
    //   if (supply.kind == thuai7_agent::SupplyKind::kBullet) {
    //     // 计算现在的位置和bullet的位置距离
    //     int curr_bullet_dis =
    //         sqrt(pow(supply.position.x - self_position_float.x, 2) +
    //              pow(supply.position.y - self_position_float.y, 2));
    //     if (curr_bullet_dis < bullet_pos_min) {
    //       bullet_pos_min = curr_bullet_dis;
    //       bullet_position_int =
    //           thuai7_agent::Position<int>{static_cast<int>(supply.position.x),
    //                                       static_cast<int>(supply.position.y)};
    //     }
    //   }
    // }

    // // 使用BFS寻路到子弹位置
    // state.path = FindPathBeFS(map, self_position_int, bullet_position_int);

    // if (!state.path.empty()) {
    //   // 获取下一个位置
    //   auto next_position_int = state.path.at(1);
    //   auto next_position = thuai7_agent::Position<float>{
    //       static_cast<float>(next_position_int.x + kFloatPositionShift),
    //       static_cast<float>(next_position_int.y + kFloatPositionShift)};

    //   // 移动到下一个位置
    //   agent.Move(next_position);
    //   spdlog::info("Moving to bullet at {}", next_position);

    //   // 如果可以拾取子弹了
    //   if (std::abs(bullet_position_int.x - self_position_float.x) <= 1.0f &&
    //       std::abs(bullet_position_int.y - self_position_float.y) <= 1.0f) {
    //     agent.PickUp(thuai7_agent::SupplyKind::kBullet, 1);
    //     spdlog::info("Got one bullet!");
    got_bullet = true;
    //   }
    // }
  }
  // 修改武器和子弹状态
  if (got_bullet && got_weapon) {
    got_weapon_and_bullet = true;
  }

  // 寻路敌方，实现攻击的逻辑
  if (got_weapon_and_bullet) {
    spdlog::info("Go and find opponent!");
    int dis_int = sqrt(pow(self_position_int.x - opponent_position_int.x, 2) +
                       pow(self_position_int.y - opponent_position_int.y, 2));
    if (std::find(state.path.begin(), state.path.end(), self_position_int) ==
            state.path.end() ||
        std::find(state.path.begin(), state.path.end(),
                  opponent_position_int) == state.path.end()) {
      state.path = FindPathBeFS(map, self_position_int, opponent_position_int);

      if (state.path.empty()) {
        spdlog::info("no path found");
        return;
      }

      spdlog::info("path: {}", state.path);
    }

    while (state.path.front() != self_position_int) {
      state.path.erase(state.path.begin());
    }

    if (state.path.size() > 1) {
      auto next_position_int = state.path.at(1);
      auto next_position = thuai7_agent::Position<float>{
          static_cast<float>(next_position_int.x + kFloatPositionShift),
          static_cast<float>(next_position_int.y + kFloatPositionShift)};

      // 只有在取到了枪和子弹的时候,而且不在自己射程内才move
      if (got_weapon_and_bullet && dis_int >= range_kAwm) {
        agent.Move(next_position);
        // TODO：在移动的过程中时刻检查自己和对方的连线中是否存在障碍物，如果没有，而且自己有枪有子弹，那么立刻开枪
        spdlog::info("moving from {} to {}", self_info.position, next_position);
      } else if (got_weapon_and_bullet && dis_int <= range_kAwm) {
        agent.Attack(opponent_info.position);
        spdlog::info("Attacked opponent!");
      }
      return;
    }
  }
}